import {Pos} from "../utils/Pos";

export default class StringIter {

    linesBuffer: string[] = [];
    ptrNext: Pos = new Pos(0, 0);
    ptr: Pos = new Pos(0, 0);

    peeked: string = "";

    constructor(str: string) {
        let strings = str.split("\n");
        strings.forEach(s => {
            this.linesBuffer.push(s + "\n");
        })
    }

    nextPos() {
        if (this.ptr.row >= this.linesBuffer.length) {
            throw new Error("advance after EOF");
        }
        if (this.ptr.col == this.linesBuffer[this.ptr.row].length - 1) {
            return new Pos(this.ptr.row + 1, 0);
        }
        return new Pos(this.ptr.row, this.ptr.col + 1);
    }

    currentPos() {
        return this.ptr;
    }

    /**
     * 获取上一个字符的位置
     */
    public previousPos(): Pos {
        if (this.ptr.row == 0 && this.ptr.col == 0) {
            throw new Error("previous position from beginning");
        }
        if (this.ptr.col == 0) {
            return new Pos(this.ptr.row - 1, this.linesBuffer[this.ptr.row - 1].length - 1);
        }
        return new Pos(this.ptr.row, this.ptr.col - 1);
    }

    /**
     * 将指针指向下一个字符，并返回当前字符
     */
    public nextChar(): string {
        if (this.peeked) {
            const ch = this.peeked;
            this.peeked = "";
            this.ptr = this.ptrNext;
            return ch;
        }

        const ch = this.getNextChar();
        this.ptr = this.ptrNext;
        return ch;
    }

    private getNextChar(): string {
        if (this.isEOF()) {
            return "";
        }
        const result = this.linesBuffer[this.ptr.row].charAt(this.ptr.col);
        this.ptrNext = this.nextPos();
        return result;
    }

    /**
     * 查看下一个字符，但不移动指针
     */
    public peekChar(): string {
        if (this.peeked) {
            return this.peeked;
        }

        const ch = this.getNextChar();
        this.peeked = ch;
        return ch;
    }

    public isEOF(): boolean {
        return this.ptr.row >= this.linesBuffer.length;
    }

    // Note: Is it evil to unread a buffer?
    public unreadLast() {
        this.ptr = this.previousPos();
    }

}